package com.imu.purse.modules.bitcoin;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
import com.imu.constant.Constant;
import com.imu.purse.bean.CoreMoneyAddr;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.net.ConnectException;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class BitcoinApi {

	private static Log log = LogFactory.get(BitcoinApi.class);
	/**
	 * 初始化参数
	 * @param moneyAddr
	 */
	private Map<String,String> initParam(CoreMoneyAddr moneyAddr){
		String cred = Base64.getUrlEncoder().encodeToString((moneyAddr.getUserName() + ":" + moneyAddr.getPwd()).getBytes());
		Map<String,String> headerMap = Maps.newHashMap();
		//身份认证
		headerMap.put("Authorization", "Basic " + cred);
		return headerMap;
	}
	
	/**
	 * 获取钱包信息
	 * @param  moneyAddrStr
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Map<String,Object> getInfo(String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getinfo", null,Object.class);
			if(result != null){
				return (Map<String,Object>)result;
			}
		}catch(Throwable e){
			log.error(e);
			Map<String,Object> rMap = new HashMap<>(1);
			rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR);
			//推送邮件
			return rMap;
		}
		return null;
	}
	
	/**
	 * 根据账号获取用户的地址，如果存在多个的时候，需要最新的一个
	 * @param phone
	 * @return
	 * @throws Throwable
	 */
	public List<String> getaddressesbyaccount(String phone,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getaddressesbyaccount", new Object[]{phone},Object.class);
			if(result != null){
				return (List<String>)result;
			}
		}catch(Throwable e){
			log.error(e);
		}
		return null;
	}

	/**
	 * 根据手机号获取新的地址
	 * @param phone
	 * @return
	 * @throws Throwable
	 */
	public String getnewaddress(String phone,CoreMoneyAddr moneyAddr){
		//初始化参数
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getnewaddress", new Object[]{phone},Object.class);
			if(result != null){
				return (String)result;
			}
		}catch(Throwable e){
			log.error(e);
		}
		return null;
	}
	/**
	 * 根据手机号获取新的地址
	 * @param phone
	 * @return
	 * @throws Throwable
	 */
	public String regaccount(String phone,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("regaccount", new Object[]{phone},Object.class);
			if(result != null){
				return (String)result;
			}
		}catch(Throwable e){
			log.error(e);
		}
		return null;
	}
	
	/**
	 * 验证用户地址是否有效
	 * @param address
	 * @return
	 * @throws Throwable
	 */
	public Map<String,Object> validateaddress(String address,String moneyAddrStr) {
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("validateaddress", new Object[]{address},Object.class);
			if(result != null){
				return (Map<String,Object>)result;
			}
		}catch(Throwable e){
			log.error(e);
			Map<String,Object> rMap = new HashMap<>(1);
			rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR);
			return rMap;
		}
		return null;
	}
	
	/**
	 * 转账
	 * @param fromAccount
	 * @param address
	 * @param money
	 * @return
	 */
	public String sendfrom(String fromAccount,String address,BigDecimal money,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		

		
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("sendfrom2", new Object[]{fromAccount,address,money},Object.class);
			if(result != null){
				return result.toString();
			}
		}catch(Throwable e){
			log.error(e);
		}
		return null;
	}
	
	/**
	 * 获取区块高度
	 * @return
	 * @throws Throwable
	 */
	public Integer getblockcount(String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);

		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getblockcount", null,Object.class);
			if(result != null){
				return (Integer)result;
			}
		}catch(Throwable e){
			log.error(e);
			//推送邮件
		}
		return null;
	}
	
	/**
	 * 根据区块高度获取区块的哈希数
	 * @param height
	 * @return
	 * @throws Throwable
	 */
	public String getblockhash(Integer height,String moneyAddrStr) {
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);

		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getblockhash", new Object[]{height},Object.class);
			if(result != null){
				return (String)result;
			}
		}catch(Throwable e){
			log.error(e);
			if(e instanceof ConnectException){//如果是连接异常代表钱包程序出问题聊
				//推送邮件
				return Constant.MONEY_PACKAGE_CONNECT_ERROR;
			}
			return Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR;
		}
		return null;
	}
	
	/**
	 * 根据区块的地址获取块的信息
	 * @param blockHash
	 * @return
	 * @throws Throwable
	 */
	public Map<String,Object> getblock(String blockHash,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);

		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getblock", new Object[]{blockHash},Object.class);
			if(result != null){
				return (Map<String,Object>)result;
			}
		}catch(Throwable e){
			log.error(e);
			Map<String,Object> rMap = new HashMap<>(1);
			rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR);
			if(e instanceof ConnectException){//如果是连接异常代表钱包程序出问题聊
				rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_ERROR);
			}
			return rMap;
		}
		return null;
	}
	
	/**
	 * 获取该块的交易信息
	 * @param tId
	 * @return
	 * @throws Throwable
	 */
	public Map<String,Object> gettransaction(String tId,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);

		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("gettransaction", new Object[]{tId},Object.class);
			if(result != null){
				return (Map<String,Object>)result;
			}
		}catch(Throwable e){
			//log.error(e);
			/*StringMap sMap = Json.decode(e.getMessage());
			return sMap.map();*/
			//log.error(e.getMessage());
			Map<String,Object> rMap = new HashMap<>(1);
			rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR);
			rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR);
			if(e instanceof ConnectException){//如果是连接异常代表钱包程序出问题聊
				rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_ERROR);
			}
			return rMap;
		}
		return null;
	}
	
	/**
	 * 获取该账号的金额
	 * @param account
	 * @param confirmNum 确认数
	 * @return
	 */
	public BigDecimal getbalance(final String account,final int confirmNum,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("getbalance", new Object[]{account},Object.class);
			if(result != null){
				return new BigDecimal(result.toString());
			}
		}catch(Throwable e){
			log.error(e);
		}
		return null;
	}

	/**
	 * 转账
	 * @param fromAccount
	 * @param address
	 * @param money
	 * @param rate
	 * @return
	 */
	public String sendfrom(String fromAccount,String address,BigDecimal money,BigDecimal rate,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("sendfrom2", new Object[]{fromAccount,address,money,rate},Object.class);
			if(result != null){
				return result.toString();
			}
		}catch(Throwable e){
			log.error("fromAccount:" + fromAccount + ",address" + address);
			log.error(e);
			return "error" + StringUtils.substringBetween(e.getMessage(),"{","}");
		}
		return null;
	}

	/**
	 * 转账，本地
	 * @param fromAccount
	 * @param address
	 * @param money
	 * @param rate
	 * @param moneyAddrStr
	 * @return
	 */
	public boolean movetoaddress(String fromAccount,String address,BigDecimal money,BigDecimal rate,String moneyAddrStr){
		CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);

		//初始化参数
		Map<String,String> headerMap = initParam(moneyAddr);
		try{
			JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()),headerMap);
			Object result = client.invoke("movetoaddress", new Object[]{fromAccount,address,money,rate},Object.class);
			if(result != null){
				return (boolean)result;
			}
		}catch(Throwable e){
			log.error(e);
			return false;
		}
		return false;
	}
} 
